package laba3;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;

/**
 * Created by Михаил on 19.05.14.
 */
public class lab3 implements Runnable{
    private JButton exitButton;
    private JButton newGameButton;
    private JButton f11;
    private JButton f12;
    private JButton f13;
    private JButton f21;
    private JButton f22;
    private JButton f23;
    private JButton f31;
    private JButton f32;
    private JButton f33;
    private JPanel XO;

    private int[][] sost;
    private boolean firstMoves;
    private boolean firstPlayer;

    private DataInputStream dataInputStream;
    private DataOutputStream dataOutputStream;

    // Добавить листенеры
    public lab3() {
        f11.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        clickField(f11, 0, 0, firstPlayer);
                    }
                });
            }
        });
        f12.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        clickField(f12,0,1,firstPlayer);
                    }
                });
            }
        });
        f13.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        clickField(f13, 0, 2, firstPlayer);
                    }
                });
            }
        });
        f21.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        clickField(f21, 1, 0, firstPlayer);
                    }
                });
            }
        });
        f22.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        clickField(f22, 1, 1, firstPlayer);
                    }
                });
            }
        });
        f23.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        clickField(f23, 1, 2, firstPlayer);
                    }
                });
            }
        });
        f31.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        clickField(f31, 2, 0, firstPlayer);
                    }
                });
            }
        });
        f32.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        clickField(f32, 2, 1, firstPlayer);
                    }
                });
            }
        });
        f33.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        clickField(f33, 2, 2, firstPlayer);
                    }
                });
            }
        });
        newGameButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                newGame(true);
            }
        });
        exitButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                try {
                    dataOutputStream.writeUTF("exit");
                    System.exit(0);
                } catch (IOException e) {
                    System.out.println("Ошибка при отправке данных на сервер.");
                    e.printStackTrace();
                    System.exit(-1);
                }
            }
        });
    }
    public lab3(String host) throws UnknownHostException, IOException, SocketException {
        this();
        int port = 6666;
        Socket socket = new Socket(host,port);
        DataInputStream dis = new DataInputStream(socket.getInputStream());
        DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
        this.dataInputStream = dis;
        this.dataOutputStream = dos;
        firstPlayer = dis.readBoolean();
    }
    // Инициализация, вывод
    @Override
    public void run() {
        JFrame f = new JFrame();
        sost = new int[3][3];
        for (int i = 0; i < 3; i++)
            for (int j = 0; j < 3; j++)
                sost[i][j] = 0;
        firstMoves = true;
        f.setTitle(firstPlayer ? "X" : "O");
        f.getContentPane().add(XO);
        f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        f.setMinimumSize(new Dimension(500, 400));
        f.pack();
        f.setVisible(true);
        
        if (!firstPlayer) {
            SwingUtilities.invokeLater(new WaitAnswer(firstPlayer));
        }
    }

    // Ждёт хода соперника и дублирует его
    private class WaitAnswer implements Runnable {
        boolean firstPlayer;
        WaitAnswer(boolean firstPlayer){
            this.firstPlayer = firstPlayer;
        }
        @Override
        public void run() {
            String[] answer;
            try {
                answer = dataInputStream.readUTF().split(" ");
                if (answer[0].equals("new")) {
                    newGame(false);
                }
                else if (answer[0].equals("exit")) {
                    try {
                        JOptionPane.showMessageDialog(new JFrame(),"Игра окончена");
                        System.exit(0);
                    } catch (HeadlessException e) {
                        System.out.println("Неизвестная ошибка при выводе сообщения.");
                        e.printStackTrace();
                        System.exit(-1);
                    }
                } else {
                    int x = Integer.parseInt(answer[1]);
                    int y = Integer.parseInt(answer[2]);
                    clickField(getButton(x,y),x,y,!firstPlayer);
                }
            } catch (NumberFormatException e) {
                System.out.println("Ошибка при обработке данных с сервера.");
                e.printStackTrace();
                System.exit(-1);
            } catch (SocketException e) {
                System.out.println("Неизвестная ошибка. Возможно, соединение было прервано");
                e.printStackTrace();
                System.exit(-1);
            } catch (IOException e) {
                System.out.println("Ошибка при обмене данными с сервером.");
                e.printStackTrace();
                System.exit(-1);
            }
        }
    }

    // Ставит Х или О. Если надо (если не "эмуляция"), отправляет на сервер. Если победа - начинает новую
    private void clickField(JButton button, int x, int y, boolean isX) {
        if ((sost[x][y] == 0)&&(firstMoves==isX)) {
            boolean res = false;
            if (isX) {
                button.setText("X");
                sost[x][y] = 1;
            } else {
                button.setText("O");
                sost[x][y] = 2;
            }
            for (int i = 0; i < 3; i++)
            {
                if (compareThreeFields(new int[][]{{i,0},{i,1},{i,2}}))
                    res = true;
                if (compareThreeFields(new int[][]{{0,i},{1,i},{2,i}}))
                    res = true;
            }
            if (compareThreeFields(new int[][]{{0,0},{1,1},{2,2}}))
                res = true;
            if (compareThreeFields(new int[][]{{0,2},{1,1},{2,0}}))
                res = true;
            try {
                if (isX == firstPlayer) {
                    // Не "эмуляция" - отправляем данные
                    dataOutputStream.writeUTF(firstPlayer + " " + x + " " + y);
                }
                if (res) {
                    String message;
                    if (isX) message = "\"X\"";
                    else message = "\"O\"";
                    message += " выиграли!";
                    JOptionPane.showMessageDialog(new JFrame(),message);
                    newGame(false);
                } else
                    firstMoves = !isX;
                // Отправили данные и не конец игры - ждём ответа
                if ((isX == firstPlayer) && (!res))
                        SwingUtilities.invokeLater(new WaitAnswer(firstPlayer));
            } catch (HeadlessException e) {
                System.out.println("Неизвестная ошибка при выводе сообщения.");
                e.printStackTrace();
                System.exit(-1);
            } catch (SocketException e) {
                System.out.println("Неизвестная ошибка. Возможно, соединение было прервано");
                e.printStackTrace();
                System.exit(-1);
            } catch (IOException e) {
                System.out.println("Ошибка при обмене данными с сервером.");
                e.printStackTrace();
                System.exit(-1);
            }
        }
    }

    private boolean compareThreeFields(int[][] ff) {
        int f[] = new int[3];
        boolean res = true;
        for (int i = 0; i < 3; i++) {
            f[i] = sost[ff[i][0]][ff[i][1]];
            if (f[i]==0) res = false;
        }
        if ((f[0]!=f[1])||(f[1]!=f[2])) res = false;
        return res;
    }
    private JButton getButton(int x, int y) {
        JButton butToPush = new JButton();
        if ((x==0)&&(y==0)) butToPush = f11;
        if ((x==0)&&(y==1)) butToPush = f12;
        if ((x==0)&&(y==2)) butToPush = f13;
        if ((x==1)&&(y==0)) butToPush = f21;
        if ((x==1)&&(y==1)) butToPush = f22;
        if ((x==1)&&(y==2)) butToPush = f23;
        if ((x==2)&&(y==0)) butToPush = f31;
        if ((x==2)&&(y==1)) butToPush = f32;
        if ((x==2)&&(y==2)) butToPush = f33;
        return butToPush;
    }

    private void newGame(boolean needSend) {
        for (int i=0; i<3; i++)
            for (int j=0; j<3; j++)
                sost[i][j] = 0;
        String emptyText = "";
        f11.setText(emptyText);f12.setText(emptyText);f13.setText(emptyText);
        f21.setText(emptyText);f22.setText(emptyText);f23.setText(emptyText);
        f31.setText(emptyText);f32.setText(emptyText);f33.setText(emptyText);
        // Отправить серверу, что новая игра, если не отправляли.
        if (needSend||(!firstPlayer))
            try {
                dataOutputStream.writeUTF("new " + needSend);
            } catch (IOException e) {
                System.out.println("Ошибка при отправке данных на сервер.");
                e.printStackTrace();
                System.exit(-1);
            }
        firstMoves = true;
        // Если второй - ждать
        if (!firstPlayer)
            SwingUtilities.invokeLater(new WaitAnswer(firstPlayer));
    }

}